#pragma once
#include "VertexAttributes.h"
#include "Runtime/Rendering/RenderResource.h"

namespace Alice
{
    enum class EVertexInputStreamType : uint8
    {
        Default = 0,
        PositionOnly,
        PositionAndNormalOnly,
        Count
    };
    class VertexFactory : public RenderResource
    {
    public:
        /**
         * Information needed to set a vertex stream.
         */
        struct FVertexStream
        {
            const VertexBuffer* VertexBuffer = nullptr;
            uint32 Offset = 0;
            uint16 Stride = 0;
            EVertexStreamUsage VertexStreamUsage = EVertexStreamUsage::Default;
            uint8 Padding = 0;

            friend bool operator==(const FVertexStream& A,const FVertexStream& B)
            {
                return A.VertexBuffer == B.VertexBuffer && A.Stride == B.Stride && A.Offset == B.Offset && A.VertexStreamUsage == B.VertexStreamUsage;
            }
            FVertexStream()
            {
            }
        };
        typedef std::array<FVertexStream,8> VertexStreamList;
        VertexStreamList mVertexStreams;
        CGIVertexDeclaration* mVertexDeclaration;
        /**
         * Creates a vertex element for a vertex stream components.  Adds a unique stream index for the vertex buffer used by the component.
         * @param Component - The vertex stream component.
         * @param AttributeIndex - The attribute index to which the stream component is bound.
         * @param AttributeIndex - Stream array where to add the new streams.
         * @return The vertex element which corresponds to Component.
         */
        template<typename VertexStreamListType>
        static FVertexElement AccessStreamComponent(const FVertexStreamComponent& Component, uint8 AttributeIndex, VertexStreamListType& InOutStreams)
        {
            FVertexStream VertexStream;
            VertexStream.VertexBuffer = Component.mVertexBuffer;
            VertexStream.Stride = Component.mStride;
            VertexStream.Offset = Component.mStreamOffset;
            VertexStream.VertexStreamUsage = Component.mVertexStreamUsage;
            return FVertexElement(0, Component.mOffset, Component.mType, AttributeIndex, VertexStream.Stride, EnumHasAnyFlags(EVertexStreamUsage::Instancing, VertexStream.VertexStreamUsage));
        }
        void InitDeclaration(const VertexDeclarationElementList & inVertexDeclarationElementList, EVertexInputStreamType StreamType = EVertexInputStreamType::Default);
    };
}
